package com.winit.schedule.task.tracker.runner;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.winit.schedule.core.model.AssignedTask;
import com.winit.schedule.core.repository.constants.TaskStatus;
import com.winit.schedule.core.task.ScheduleTaskDeal;
import com.winit.schedule.core.task.ScheduleTaskDealMulti;
import com.winit.schedule.core.task.ScheduleTaskDealSingle;
import com.winit.schedule.core.task.ScheduleTaskDefine;
import com.winit.schedule.core.utils.Clock;
import com.winit.schedule.task.tracker.TaskTracker;

/**
 * 抽象任务管理器
 * 
 * @author jianke.zhang 2015-4-22 上午9:52:58
 * @since 1.0
 */
@SuppressWarnings("rawtypes")
public abstract class AbstractTaskManager implements StrategyTask {

    private static transient Logger log                 = LoggerFactory.getLogger(AbstractTaskManager.class);

    /**
     * 用户标识不同线程的序号
     */
    private static int              nextSerialNumber    = 0;

    /**
     * 当前线程组编号
     */
    protected int                   currentSerialNumber = 0;

    /**
     * 调到任务
     */
    protected AssignedTask          task;

    ScheduleTaskDefine              scheduleTaskDefine;

    /**
     * 队列处理器
     */
    ScheduleTaskDeal                taskDealBean;

    /**
     * 多线程任务处理器
     */
    TaskRunner                      taskRunner;

    /**
     * 运行分析
     */
    StatisticsInfo                  statisticsInfo      = new StatisticsInfo();

    /**
     * 是否停止执行
     */
    protected boolean               isStop              = false;

    private TaskTracker             taskTracker;

    private long                    registerTime;

    @SuppressWarnings("unchecked")
    public AbstractTaskManager(TaskTracker taskTracker, AssignedTask task) throws Exception{
        registerTime = Clock.getSystemTime();
        this.currentSerialNumber = serialNumber();
        this.taskTracker = taskTracker;
        this.task = task;
        this.scheduleTaskDefine = task.getTaskDefine();

        Object dealBean = null;
        if (dealBean == null && taskTracker != null) {
            dealBean = taskTracker.getBean(ScheduleTaskDefine.BEAN_PREFIX + this.scheduleTaskDefine.getTaskName());
        }
        if (dealBean == null) {
            dealBean = Class.forName(this.scheduleTaskDefine.getTaskDealClass()).newInstance();
        }

        if (dealBean == null) {
            throw new Exception("class :" + this.scheduleTaskDefine.getClass() + " newInstance failure");
        }

        if ((dealBean instanceof ScheduleTaskDeal) == false) {
            throw new Exception("SpringBean " + this.scheduleTaskDefine.getTaskName()
                                + " not implements ScheduleTaskDeal");
        }

        this.taskDealBean = (ScheduleTaskDeal) dealBean;

        if (dealBean instanceof ScheduleTaskDealMulti) {
            taskRunner = new MultiThreadTaskRunner(this, (ScheduleTaskDealMulti) this.taskDealBean, statisticsInfo);
        } else if (dealBean instanceof ScheduleTaskDealSingle) {
            taskRunner = new SingleThreadTaskRunner(this, (ScheduleTaskDealSingle) this.taskDealBean, statisticsInfo);
        }
    }

    /**
     * 终止任务
     */
    @Override
    public void stop(boolean force) {
        if (log.isDebugEnabled()) {
            log.debug("stop task ：" + this.task.getTaskId());
        }
        this.isStop = true;
        if (this.taskRunner != null) {
            try {
                this.taskRunner.stopTask(force);
            } catch (Exception e) {
                log.error("Stop task runner failure, taskRunnerId:" + this.getTaskRunnerUuid() + ", taskID is:"
                          + this.task.getTaskId().getId());
            }
        }
    }

    public int getThreadNum() {
        return taskRunner.getThreadNum();
    }

    /**
     * 超时触发
     * 
     * @throws Exception
     */
    public void completeSchedule(boolean forceStop) throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("stop task ：" + this.task.getTaskId());
        }
        this.isStop = true;
        if (this.taskRunner != null) {
            try {
                this.taskRunner.completeSchedule();
            } catch (Exception e) {
                log.error("Stop task runner failure, taskRunnerId:" + this.getTaskRunnerUuid() + ", taskID is:"
                          + this.task.getTaskId().getId());
            }
        }
    }

    private static synchronized int serialNumber() {
        return nextSerialNumber++;
    }

    public int getCurrentSerialNumber() {
        return this.currentSerialNumber;
    }

    public long getRegisterTime() {
        return registerTime;
    }

    public StatisticsInfo getStatisticsInfo() {
        return statisticsInfo;
    }

    public boolean isContinueWhenNoData() throws Exception {
        if (isStopWhenNoData() == true) {
            this.completeSchedule(true);
            return false;
        } else {
            return true;
        }
    }

    private boolean isStopWhenNoData() {
        // 如果还没有分配到任务队列则不能退出
        if (this.task.getTaskItems().size() > 0 && this.task.getPermitRunStartTime() != 0) {
            if (this.task.getPermitRunEndTime() <= 0) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public boolean isSleeping() {
        return this.taskRunner.isSleeping();
    }

    public AssignedTask getTask() {
        return task;
    }

    public ScheduleTaskDefine getScheduleTaskDefine() {
        return scheduleTaskDefine;
    }

    public TaskTracker getTaskTracker() {
        return taskTracker;
    }

    public String getTaskRunnerUuid() {
        return this.getTaskTracker().getUuid() + "$" + currentSerialNumber;
    }

    @Override
    public boolean isStop() {
        return this.isStop;
    }

    protected abstract void completeTask(TaskStatus taskStatus, String exception);

    protected abstract void fireTaskExecuteFailure(String exception);

}
